package com.zmn.mcc.business.impl.role;

import com.alibaba.fastjson.JSONObject;
import com.zmn.base.plat.engine.common.constant.PlatEngineConsts;
import com.zmn.base.plat.engine.common.exception.ZmnPlatException;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.business.interfaces.role.RoleBService;
import com.zmn.mcc.business.interfaces.staff.StaffBService;
import com.zmn.mcc.business.interfaces.staff.ip.StaffIpInfoBService;
import com.zmn.mcc.cache.DeptCache;
import com.zmn.mcc.cache.RoleCache;
import com.zmn.mcc.cache.SysCache;
import com.zmn.mcc.common.constant.RoleChangeLogDict;
import com.zmn.mcc.common.constant.RoleDict;
import com.zmn.mcc.common.dto.role.RoleDIO;
import com.zmn.mcc.common.dto.role.RoleDRO;
import com.zmn.mcc.manager.config.MccConfig;
import com.zmn.mcc.model.dto.permit.ModuleSimpleDO;
import com.zmn.mcc.model.dto.permit.PermitSimpleDO;
import com.zmn.mcc.model.entity.dept.McDept;
import com.zmn.mcc.model.entity.log.IpInfo;
import com.zmn.mcc.model.entity.module.McModule;
import com.zmn.mcc.model.entity.permit.McPermit;
import com.zmn.mcc.model.entity.permit.McPermitQuery;
import com.zmn.mcc.model.entity.role.*;
import com.zmn.mcc.model.entity.staff.McStaff;
import com.zmn.mcc.model.entity.sys.McSys;
import com.zmn.mcc.services.interfaces.dept.DeptService;
import com.zmn.mcc.services.interfaces.module.ModuleService;
import com.zmn.mcc.services.interfaces.permit.PermitService;
import com.zmn.mcc.services.interfaces.role.*;
import com.zmn.mcc.services.interfaces.staff.StaffService;
import com.zmn.mcc.services.interfaces.sys.SysService;
import com.zmn.mcc.utils.CompareFiledsUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author heguanghua
 * @since 2020/04/14 22:21
 */
@Service
public class RoleBServiceImpl implements RoleBService {
    protected Logger logger = LoggerFactory.getLogger(RoleBServiceImpl.class);

    // region Resource
    @Resource
    private PermitService permitService;
    @Resource
    private ModuleService moduleService;
    @Resource
    private RoleService roleService;
    @Resource
    private StaffService staffService;
    @Resource
    private StaffBService staffBService;
    @Resource
    private DeptService deptService;
    @Resource
    private SysService sysService;
    @Resource
    private RoleSysService roleSysService;
    @Resource
    private RoleModuleService roleModuleService;
    @Resource
    private RolePermitService rolePermitService;
    @Resource
    private RoleStaffService roleStaffService;
    @Resource
    private DeptCache deptCache;
    @Resource
    private RoleCache roleCache;
    @Resource
    private MccConfig config;
    @Resource
    private RoleChangeLogService roleChangeLogService;
    @Resource
    private StaffIpInfoBService staffIpInfoBService;
    @Autowired
    private SysCache sysCache;
    // endregion

    BeanCopier droCopier = BeanCopier.create(McRole.class, RoleDRO.class, false);
    BeanCopier queryCopier = BeanCopier.create(RoleDIO.class, McRoleQuery.class, false);


    @Override
    @ReadOnlyConnection
    public ResponseDTO listModulePermit(Integer roleId, Integer operatorId, Integer status) {

        // region 校验参数

        // 必须指定角色ID
        if (NumberUtil.isNullOrZero(roleId)) {
            return ResponseDTO.fail("未指定角色");
        }
        // 必须指定员工ID
        if (NumberUtil.isNullOrZero(operatorId)) {
            return ResponseDTO.fail("未指定员工");
        }
        // endregion

        // region 识别操作人是否拥有"系统全局角色"、"超级管理员"或"权限管理员角色"

        // 操作人可用的角色ID
        //List<Integer> staffRoleIds = roleStaffService.listRoleIdByStaffId(operatorId);

        /**
         * 操作人是否拥有"超级管理员角色"
         */
        boolean isSuperAdmin = staffBService.isSuperAdmin(operatorId);

        /**
         * 操作人是否拥有"系统全局角色"
         * 如操作人无"系统全局角色"，则只可分配其所属部门默认角色的权限
         */
        boolean isGlobalAdmin = isSuperAdmin ? true : staffBService.isGlobalAdmin(operatorId);
        List<Integer> deptPermitIds = new ArrayList<>();
        if (!isGlobalAdmin) {
            McStaff staff = staffService.findByKey(operatorId);
            McDept dept = deptService.findByKey(staff.getDeptId());
            deptPermitIds = rolePermitService.listPermitIdByRoleId(dept.getRoleId());
        }

        /**
         * 操作人是否拥有"权限管理员角色"
         * 如操作人无"权限管理员角色"，则排除"权限管理员角色的权限清单"内的权限
         */
        boolean isAssignAdmin = isSuperAdmin ? true : staffBService.isAssignAdmin(operatorId);
        List<Integer> assignPermitIds = config.getAssignAdminPermitIds();
        // endregion

        List<ModuleSimpleDO> items = new ArrayList<>();

        // 全部可用系统/模块/权限
        List<McSys> syses = sysService.listAll(status);
        List<McModule> modules = moduleService.listAll(status);
        List<McPermit> permits = permitService.listAll(status);

        // region 系统与模块

        // 有序map
        Map<Integer, ModuleSimpleDO> sysMap = new LinkedHashMap<>();
        Map<Integer, ModuleSimpleDO> moduleMap = new LinkedHashMap<>();

        // 系统(转换为顶级模块)
        syses.forEach(item -> {
            ModuleSimpleDO module = new ModuleSimpleDO();
            module.setModuleId(item.getSysId() >= 1000 ? item.getSysId() - 500 : item.getSysId());  // 系统id与模块id重复，导致bug，临时解决：-500；否则重新设计
            module.setModuleName(item.getSysName());
            module.setParentId(0);
            module.setSysId(item.getSysId());
            module.setLevel(0);
            module.setStatus(item.getStatus());
            //module.setChecked(false);
            //items.add(module);
            sysMap.put(module.getModuleId(), module);
        });

        for (McModule item : modules) {
            if (NumberUtil.isNullOrZero(item.getSysId())) {
                continue;
            }
            // 如果模块的父ID为1，则更改为系统ID，此处注意，系统主键ID必须都小于模块ID
            if (item.getParentId() == GlobalConsts.TOP_ID) {
                item.setParentId(item.getSysId() >= 1000 ? item.getSysId() - 500 : item.getSysId());  // 系统id与模块id重复，导致bug，临时解决：-500；否则重新设计
            }
            ModuleSimpleDO module = new ModuleSimpleDO();
            module.setModuleId(item.getModuleId());
            module.setModuleName(item.getModuleName());
            module.setParentId(item.getParentId());
            module.setSysId(item.getSysId());
            module.setLevel(item.getLevel() == null ? 1 : item.getLevel());
            module.setStatus(item.getStatus());

            moduleMap.put(module.getModuleId(), module);
        }
        // endregion

        // region 过滤可分配权限

        // 当前角色已分配权限ID
        List<Integer> rolePermitIds = rolePermitService.listPermitIdByRoleId(roleId);

        // 模块所属系统ID集合
//        Set<Integer> permitSysIds = new HashSet<>();

        // 权限所属模块ID集合
//        Set<Integer> permitModuleIds = new HashSet<>();

        for (McPermit item : permits) {

            // 必须具备sysId和moduleId
            if (NumberUtil.isNullOrZero(item.getSysId()) || NumberUtil.isNullOrZero(item.getModuleId())) {
                continue;
            }

            // "权限管理员角色的权限清单"内的权限(特殊权限)，操作人无"超级管理员角色"，或当前角色非"超级管理员"或非"权限管理员"
            if (assignPermitIds.contains(item.getPermitId())) {
                if (!isSuperAdmin || !(roleId.equals(config.getSuperAdminRoleId()) || roleId.equals(config.getAssignAdminRoleId()))) {
                    continue;
                }
            }

            // 操作人无"系统全局角色"，则过滤部门默认角色权限外的权限
            if (!isGlobalAdmin && !deptPermitIds.contains(item.getPermitId())) {
                continue;
            }

            PermitSimpleDO permit = new PermitSimpleDO();
            permit.setPermitId(item.getPermitId());
            permit.setPermitName(item.getPermitName());
            permit.setModuleId(item.getModuleId());
            permit.setSysId(item.getSysId());
            permit.setStatus(item.getStatus());

            // 当前角色已有该权限，则选中
            boolean checked = rolePermitIds.contains(permit.getPermitId());
            permit.setChecked(checked);

            // 所属系统
            ModuleSimpleDO sys = sysMap.get(permit.getSysId() >= 1000 ? permit.getSysId() - 500 : permit.getSysId());
            if (sys == null) {
                continue;
            }
            if (checked) {
                sys.setChecked(true);
            }

            // 所属模块
            ModuleSimpleDO module = moduleMap.get(permit.getModuleId());
            if (module == null) {
                continue;
            }
            if (checked) {
                module.setChecked(true);
            }
            module.getPermits().add(permit);

            // 权限所属系统ID集合/模块ID集合
//            permitSysIds.add(permit.getSysId());
//            permitModuleIds.add(permit.getModuleId());
        }
        // endregion

        /**
         * 加入返回的系统集/模块集
         * 按照原始顺序迭代
         * 部门权限管理时显示了无用模块，待优化
         */
        for (Map.Entry<Integer, ModuleSimpleDO> entry : sysMap.entrySet()) {
//            if (permitSysIds.contains(entry.getKey())) {
//                items.add(entry.getValue());
//            }
            items.add(entry.getValue());
        }
        for (Map.Entry<Integer, ModuleSimpleDO> entry : moduleMap.entrySet()) {
//            if (permitModuleIds.contains(entry.getKey())) {
//                items.add(entry.getValue());
//            }
            items.add(entry.getValue());
        }

        return ResponseDTO.success(items, "OK");
    }
    // endregion


    // region查询角色列表

    @Override
    public List<RoleDRO> listByDIO(RoleDIO roleDIO) {
        // 对象转换
        McRoleQuery roleQuery = new McRoleQuery();
        queryCopier.copy(roleDIO, roleQuery, null);

        List<McRole> roleList = roleService.listByQuery(roleQuery);

        List<RoleDRO> retList = getRoleDROS(roleList);
        return retList;
    }

    @Override
    public List<RoleDRO> listByIds(List<Integer> ids) {

        List<McRole> roleList = roleService.listByIds(ids);
        List<RoleDRO> retList = getRoleDROS(roleList);
        return retList;
    }

    // region 新增/修改角色

    @Override
    public ResponseDTO addRole(McRole role) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkRole(role);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initRole(role);

            // 角色信息
            roleService.insert(role);

            // 更新缓存
            roleCache.setRole(role.getRoleId());
            if (role.getType() == RoleDict.ROLE_TYPE_GLOBAL) {
                roleCache.setGlobalRoleIds();
            }

            return ResponseDTO.success(role.getRoleId(), "新增角色成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]新增角色失败,role:[%s],ex:[%s]", JSONObject.toJSONString(role), ex.getMessage()));
            return ResponseDTO.fail("新增角色失败");
        }
    }

    @Override
    public ResponseDTO modifyRole(McRole role) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkRole(role);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initRole(role);

            //记录编辑信息
            addRoleLog(role);

            // 角色信息
            roleService.updateByKey(role);

            // 更新缓存
            roleCache.setRole(role.getRoleId());

            return ResponseDTO.success(role.getRoleId(), "修改角色成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]修改角色失败,role:[%s],ex:[%s]", JSONObject.toJSONString(role), ex.getMessage()));
            return ResponseDTO.fail("修改角色失败");
        }
    }

    /**
     * 记录变化日志
     *
     * @param role
     */
    private void addRoleLog(McRole role) {
        McRole beforeRole = roleService.findByKey(role.getRoleId());
        String[] compare = new String[]{"roleName", "exportLimit", "dayLimit", "numberLimit", "remark"};
        Map<String, Map> map = CompareFiledsUtils.compareFields(beforeRole, role, compare);
        StringBuilder before = new StringBuilder();
        StringBuilder after = new StringBuilder();
        //部门特殊处理
        if (!Objects.equals(beforeRole.getDeptId(), role.getDeptId())) {
            McDept beforeD = Optional.ofNullable(deptService.findByKey(beforeRole.getDeptId())).orElse(new McDept());
            McDept afterD = Optional.ofNullable(deptService.findByKey(role.getDeptId())).orElse(new McDept());
            before.append("部门:" + beforeD.getDeptName() + PlatEngineConsts.SPLITER_DEFAULT);
            after.append("部门:" + afterD.getDeptName() + PlatEngineConsts.SPLITER_DEFAULT);
        }
        if (MapUtils.isNotEmpty(map)) {
            map.forEach((k, v) -> {
                before.append(RoleChangeLogDict.getRoleChangeLogFildName(k) + PlatEngineConsts.COLON + v.get("objBefore") + PlatEngineConsts.SPLITER_DEFAULT);
                after.append(RoleChangeLogDict.getRoleChangeLogFildName(k) + PlatEngineConsts.COLON + v.get("objAfter") + PlatEngineConsts.SPLITER_DEFAULT);
            });
        }
        if (StringUtils.isNotBlank(before.toString()) || StringUtils.isNotBlank(after.toString())) {
            McStaff operator = staffService.findByKey(role.getStaffId());
            IpInfo ipInfo = staffIpInfoBService.locationByIP(role.getIp());
            McRoleChangeLog changeLog = McRoleChangeLog.builder()
                    .roleId(role.getRoleId()).beforContent(before.toString()).afterContent(after.toString())
                    .abutmenterId(role.getStaffId()).abutmenter(operator.getRealName())
                    .abutmenterDeptId(String.valueOf(operator.getDeptId())).abutmenterDeptName(operator.getDeptName())
                    .changeType(RoleChangeLogDict.ROLE_CHANGE_LOG_TYPE_1).ip(role.getIp())
                    .abutmenterCity(ipInfo != null ? ipInfo.getProvince() + "-" + ipInfo.getCity() : "").createTime(new Date()).build();
            roleChangeLogService.insert(changeLog);
        }
    }

    /**
     * 校验角色信息
     *
     * @param role
     * @return
     */
    private ResponseDTO checkRole(McRole role) {

        if (StringUtil.isBlank(role.getRoleName())) {
            return ResponseDTO.fail("角色名称不能为空");
        }

        return ResponseDTO.success(null, "OK");
    }

    /**
     * 初始化角色
     *
     * @param role
     */
    private void initRole(McRole role) {

        // 数据导出数量上限
        if (NumberUtil.isNullOrZero(role.getExportLimit())) {
            role.setExportLimit(0);
        }

        // 角色类型
        this.initRoleType(role);

        // 部门内部角色，没有选择部门则默认为操作人所属部门
        if (role.getType() == RoleDict.ROLE_TYPE_INSIDE) {
            if (NumberUtil.isNullOrZero(role.getDeptId())) {
                McStaff operator = staffService.findByKey(role.getStaffId());
                role.setDeptId(operator.getDeptId());
            }
        }
        // 系统全局角色没有部门归属
        else if (role.getType() == RoleDict.ROLE_TYPE_GLOBAL) {
            role.setDeptId(null);
        }
    }

    // 初始化角色类型
    private void initRoleType(McRole role) {

        // 仅用于新增角色
        if (NumberUtil.isNotNullOrZero(role.getRoleId())) {
            return;
        }

        // 检查角色类型
        if (NumberUtil.isNullOrZero(role.getType())) {
            role.setType(RoleDict.ROLE_TYPE_INSIDE);
        }
        if (role.getType() == RoleDict.ROLE_TYPE_INSIDE) {
            return;
        }

        /**
         * 校验操作人是否有"超级管理员角色"，只有"超级管理员角色"才能创建"系统全局角色"
         * 如没有，则强制修改角色类型为"部门内部角色"
         */
        boolean isSuperAdmin = staffBService.isSuperAdmin(role.getStaffId());
        if (!isSuperAdmin) {
            role.setType(RoleDict.ROLE_TYPE_INSIDE);
        }
    }
    // endregion

    // region 为角色分配权限

    @Override
    public ResponseDTO assignPermitBatch(Integer roleId, List<Integer> permitIds, Integer operatorId, String ip) {

        // region 校验参数

        if (NumberUtil.isNullOrZero(roleId)) {
            return ResponseDTO.fail("未指定角色");
        }
        if (CollectionUtil.isNullOrEmpty(permitIds)) {
            return ResponseDTO.fail("未指定要分配的权限");
        }
        if (NumberUtil.isNullOrZero(operatorId)) {
            return ResponseDTO.fail("没有操作人");
        }
        // endregion

        try {

            // 要分配的有效权限集合
            List<Integer> validPermitIds = new ArrayList<>();

            // region 过滤要分配的权限

            // 操作人可用的角色ID
            List<Integer> staffRoleIds = roleStaffService.listRoleIdByStaffId(operatorId);

            /**
             * 操作人是否拥有"系统全局角色"
             * 如操作人无"系统全局角色"，则只可分配其所属部门默认角色的权限
             */
            boolean isGlobalAdmin = staffBService.isGlobalAdmin(operatorId);
            List<Integer> deptPermitIds = new ArrayList<>();
            if (!isGlobalAdmin) {
                McStaff staff = staffService.findByKey(operatorId);
                McDept dept = deptService.findByKey(staff.getDeptId());
                deptPermitIds = rolePermitService.listPermitIdByRoleId(dept.getRoleId());
                if (!this.checkDeptRole(roleId, dept)) {
                    return ResponseDTO.fail("您没有该角色的修改权限");
                }
            }

            /**
             * 操作人是否拥有"权限管理员角色"
             * 如操作人无"权限管理员角色"，则排除"权限管理员角色的权限清单"内的权限
             */
            boolean isAssignAdmin = staffBService.isAssignAdmin(operatorId);
            List<Integer> assignPermitIds = config.getAssignAdminPermitIds();

            // 过滤权限
            for (int permitId : permitIds) {
                if ((!isGlobalAdmin && !deptPermitIds.contains(permitId))
                        || (!isAssignAdmin && assignPermitIds.contains(permitId))) {
                    continue;
                }
                validPermitIds.add(permitId);
            }
            // endregion

            // 全部可用权限
            List<McPermit> permits = permitService.listAll(GlobalDict.STATUS_ENABLE);

            // region 最终用于分配的系统/模块/角色
            Set<Integer> roleSysIds = new HashSet<>();
            Set<Integer> roleModuleIds = new HashSet<>();
            Set<Integer> rolePermitIds = new HashSet<>();
            for (McPermit permit : permits) {

                if (NumberUtil.isNullOrZero(permit.getSysId()) || NumberUtil.isNullOrZero(permit.getModuleId())) {
                    continue;
                }
                if (!validPermitIds.contains(permit.getPermitId())) {
                    continue;
                }

                roleSysIds.add(permit.getSysId());
                roleModuleIds.add(permit.getModuleId());
                rolePermitIds.add(permit.getPermitId());
            }
            // endregion


            //记录角色管理变动日志
            addRoleChangeLog(roleId, operatorId, ip, rolePermitIds);

            //region 删除角色原已分配的系统/模块/权限
            roleSysService.deleteByRoleId(roleId);
            roleModuleService.deleteByRoleId(roleId);
            rolePermitService.deleteByRoleId(roleId);
            // endregion

            //region 重新写入分配的系统/模块/权限

            List<McRoleSys> roleSyses = new ArrayList<>();
            for (int sysId : roleSysIds) {
                roleSyses.add(new McRoleSys(roleId, sysId));
            }
            roleSysService.insertByBatch(roleSyses);

            List<McRoleModule> roleModules = new ArrayList<>();
            for (int moduleId : roleModuleIds) {
                roleModules.add(new McRoleModule(roleId, moduleId));
            }
            roleModuleService.insertByBatch(roleModules);

            List<McRolePermit> rolePermits = new ArrayList<>();
            for (int permitId : rolePermitIds) {
                rolePermits.add(new McRolePermit(roleId, permitId));
            }
            rolePermitService.insertByBatch(rolePermits);
            // endregion

            logger.info(String.format("[ZMN]为角色分配权限成功,roleId:[%s],permitIds:[%s],validPermitIds:[%s],operatorId:[%s]",
                    roleId, permitIds.toString(), validPermitIds.toString(), operatorId));
            return ResponseDTO.success(null, "为角色分配权限成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]为角色分配权限出错,roleId:[%s],permitIds:[%s],operatorId:[%s],ex:[%s]",
                    roleId, permitIds.toString(), operatorId, ex.getMessage()));
            return ResponseDTO.fail("为角色分配权限失败");
        }
    }

    /**
     * 记录权限变更日志
     *
     * @param roleId
     * @param operatorId
     * @param ip
     */
    private void addRoleChangeLog(Integer roleId, Integer operatorId, String ip, Set<Integer> rolePermitIds) {
        Map<Integer, McSys> mcSysMap = Optional.ofNullable(sysCache.listApp()).orElse(Collections.emptyList())
                .stream().collect(Collectors.toMap(McSys::getSysId, e -> e));
        List<McModule> mcModules = Optional.ofNullable(moduleService.listAll(PlatEngineConsts.STATUS_VALID)).orElse(Collections.emptyList());
        StringBuilder after = new StringBuilder();

        List<Integer> beforePerimitIds = rolePermitService.listPermitIdByRoleId(roleId);

        List unionPermitIds = (List) CollectionUtils.union(beforePerimitIds, rolePermitIds);
        List intersectionPermitIds = (List) CollectionUtils.intersection(beforePerimitIds, rolePermitIds);
        List<Integer> subtractPermitIds = (List) CollectionUtils.subtract(unionPermitIds, intersectionPermitIds);

        List<McPermit> mcPermits = Collections.emptyList();
        if (CollectionUtils.isNotEmpty(subtractPermitIds)) {
            McPermitQuery mcPermitQuery = new McPermitQuery();
            mcPermitQuery.setPermitIds(subtractPermitIds);
            mcPermits = Optional.ofNullable(permitService.listByQuery(mcPermitQuery)).orElse(Collections.emptyList());
        }

        if (CollectionUtils.isEmpty(mcPermits)) {
            return;
        }
        List<Integer> sysIds = mcPermits.stream().map(McPermit::getSysId).distinct().collect(Collectors.toList());
        List<Integer> moduleIds = mcPermits.stream().map(McPermit::getModuleId).distinct().collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(sysIds) && MapUtils.isNotEmpty(mcSysMap)) {
            for (Integer roleSysId : sysIds) {
                after.append(PlatEngineConsts.LEFT_PARENTHESIS);
                after.append(mcSysMap.get(roleSysId) != null ? mcSysMap.get(roleSysId).getSysName() : PlatEngineConsts.SPLITER_EMPTY);
                //该系统下的模块
                List<String> sysModule = mcModules.stream().filter(e -> Objects.equals(roleSysId, e.getSysId()))
                        .filter(e -> moduleIds.contains(e.getModuleId())).map(McModule::getModuleName).collect(Collectors.toList());
                after.append(PlatEngineConsts.COLON).append(StringUtils.join(sysModule, PlatEngineConsts.SPLITER_DEFAULT));
                after.append(PlatEngineConsts.RIGHT_PARENTHESIS + PlatEngineConsts.SPLITER_DEFAULT);
            }
        }
        //记录日志
        if (StringUtils.isNotBlank(after.toString())) {
            McStaff operator = staffService.findByKey(operatorId);
            IpInfo ipInfo = staffIpInfoBService.locationByIP(ip);
            McRoleChangeLog changeLog = McRoleChangeLog.builder()
                    .roleId(roleId).beforContent(PlatEngineConsts.SPLITER_EMPTY).afterContent(after.toString())
                    .abutmenterId(operatorId).abutmenter(operator.getRealName())
                    .abutmenterDeptId(String.valueOf(operator.getDeptId())).abutmenterDeptName(operator.getDeptName())
                    .changeType(RoleChangeLogDict.ROLE_CHANGE_LOG_TYPE_2).ip(ip)
                    .abutmenterCity(ipInfo != null ? ipInfo.getProvince() + "-" + ipInfo.getCity() : "").createTime(new Date()).build();
            roleChangeLogService.insert(changeLog);
        }
    }

    // endregion

    // region 校验角色是否属于操作人及下级部门

    @Override
    public boolean checkDeptRole(Integer roleId, McDept operatorDept) {

        // 校验是否为部门默认角色
        if (NumberUtil.isNotNullOrZero(operatorDept.getRoleId()) && operatorDept.getRoleId().equals(roleId)) {
            return true;
        }

        // 校验本部门下的其他角色
        List<McRole> roles = roleService.listByDeptId(operatorDept.getDeptId(), GlobalDict.STATUS_ENABLE);
        for (McRole role : roles) {
            if (role.getRoleId().equals(roleId)) {
                return true;
            }
        }

        // 校验下级部门默认角色及其他角色
        List<McDept> depts = deptService.listByParentId(operatorDept.getDeptId(), GlobalDict.STATUS_ENABLE);
        for (McDept dept : depts) {
            if (this.checkDeptRole(roleId, dept)) {
                return true;
            }
        }

        return false;
    }


    private List<RoleDRO> getRoleDROS(List<McRole> roleList) {
        List<RoleDRO> retList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(roleList)) {
            for (McRole role : roleList) {
                RoleDRO dro = new RoleDRO();
                droCopier.copy(role, dro, null);
                retList.add(dro);
            }
        }
        return retList;
    }
    // endregion


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean copy(Integer roleId, String ids) {

        McRole role = roleService.findByKey(roleId);
        if (Objects.isNull(role)) {
            throw new ZmnPlatException("无效的数据");
        }


        List<Integer> idArr = StringUtil.convertStrsToList(ids);
        if (idArr.size() > 50) {
            throw new ZmnPlatException("批量复制不能超过50个");
        }

        List<McRole> mcRoles = roleService.listByIds(idArr);

        if (CollectionUtil.isNullOrEmpty(mcRoles)) {
            throw new ZmnPlatException("无效的数据");
        }

        // 查询需要复制的所有的权限
        List<Integer> permitIds = rolePermitService.listPermitIdByRoleId(roleId);
        if (CollectionUtil.isNullOrEmpty(permitIds)) {
            throw new ZmnPlatException("无效的数据");
        }

        // 便利
        mcRoles.forEach(x -> {
            Integer copyRoleId = x.getRoleId();
            List<McRolePermit> rolePermits = permitIds.stream().map(i -> new McRolePermit(copyRoleId, i)).collect(Collectors.toList());
            // 先删除
            rolePermitService.deleteByRoleId(x.getRoleId());
            // 新增
            rolePermitService.insertByBatch(rolePermits);
        });

        return true;
    }
}
